#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
自动下载dex2jar并转换dex文件为jar
"""
import os
import sys
import zipfile
import urllib.request
import subprocess
from pathlib import Path

DEX2JAR_VERSION = "v2.4"
DEX2JAR_URL = f"https://github.com/pxb1988/dex2jar/releases/download/{DEX2JAR_VERSION}/dex-tools-{DEX2JAR_VERSION}.zip"
DEX2JAR_ALT_URL = "https://github.com/pxb1988/dex2jar/files/12892749/dex-tools-v2.4.zip"
DEX2JAR_DIR = "dex-tools"

def download_dex2jar():
    """下载dex2jar工具"""
    if os.path.exists(DEX2JAR_DIR):
        print(f"✓ dex2jar已存在: {DEX2JAR_DIR}")
        return True
    
    print("=" * 70)
    print("下载dex2jar工具".center(70))
    print("=" * 70)
    print(f"下载地址: {DEX2JAR_URL}")
    print("正在下载...")
    
    try:
        zip_path = "dex-tools.zip"
        
        # 下载文件
        def show_progress(block_num, block_size, total_size):
            downloaded = block_num * block_size
            percent = min(downloaded * 100 / total_size, 100)
            sys.stdout.write(f"\r进度: {percent:.1f}% ({downloaded}/{total_size} 字节)")
            sys.stdout.flush()
        
        urllib.request.urlretrieve(DEX2JAR_URL, zip_path, show_progress)
        print("\n✓ 下载完成")
        
        # 解压
        print("正在解压...")
        with zipfile.ZipFile(zip_path, 'r') as zip_ref:
            zip_ref.extractall('.')
        
        # 重命名目录
        extracted_dir = f"dex-tools-{DEX2JAR_VERSION}"
        if os.path.exists(extracted_dir):
            os.rename(extracted_dir, DEX2JAR_DIR)
        
        # 删除zip文件
        os.remove(zip_path)
        
        print(f"✓ dex2jar已安装到: {DEX2JAR_DIR}")
        return True
        
    except Exception as e:
        print(f"\n✗ 下载失败: {e}")
        print("\n请手动下载:")
        print(f"  1. 访问: {DEX2JAR_URL}")
        print(f"  2. 解压到当前目录")
        print(f"  3. 重命名文件夹为: {DEX2JAR_DIR}")
        return False

def convert_dex_to_jar(dex_file, output_dir="jar_output"):
    """使用dex2jar转换单个dex文件"""
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # 构建dex2jar命令
    if sys.platform == 'win32':
        d2j_script = os.path.join(DEX2JAR_DIR, "d2j-dex2jar.bat")
    else:
        d2j_script = os.path.join(DEX2JAR_DIR, "d2j-dex2jar.sh")
        os.chmod(d2j_script, 0o755)  # 添加执行权限
    
    if not os.path.exists(d2j_script):
        print(f"✗ 找不到dex2jar脚本: {d2j_script}")
        return False
    
    # 输出jar文件名
    dex_name = os.path.basename(dex_file)
    jar_name = dex_name.replace('.dex', '.jar')
    jar_path = os.path.join(output_dir, jar_name)
    
    # 如果已存在，跳过
    if os.path.exists(jar_path):
        print(f"  [跳过] {jar_name} (已存在)")
        return True
    
    print(f"  [转换] {dex_name} -> {jar_name}")
    
    try:
        # 执行转换
        cmd = [d2j_script, dex_file, "-o", jar_path, "--force"]
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0 and os.path.exists(jar_path):
            size = os.path.getsize(jar_path)
            print(f"  ✓ 成功: {jar_name} ({size:,} 字节)")
            return True
        else:
            print(f"  ✗ 失败: {result.stderr}")
            return False
            
    except Exception as e:
        print(f"  ✗ 转换失败: {e}")
        return False

def convert_all_dex(source_dir="merged_dex", output_dir="jar_output"):
    """转换目录中的所有dex文件"""
    print("\n" + "=" * 70)
    print("Dex转Jar".center(70))
    print("=" * 70)
    
    if not os.path.exists(source_dir):
        print(f"✗ 目录不存在: {source_dir}")
        return
    
    # 查找所有dex文件
    dex_files = sorted([f for f in os.listdir(source_dir) if f.endswith('.dex')])
    
    if not dex_files:
        print(f"✗ 在 {source_dir} 中没有找到dex文件")
        return
    
    print(f"\n找到 {len(dex_files)} 个dex文件")
    print(f"源目录: {source_dir}")
    print(f"输出目录: {output_dir}\n")
    
    # 转换每个dex文件
    success_count = 0
    for dex_file in dex_files:
        dex_path = os.path.join(source_dir, dex_file)
        if convert_dex_to_jar(dex_path, output_dir):
            success_count += 1
    
    print("\n" + "=" * 70)
    print(f"转换完成: {success_count}/{len(dex_files)} 个文件成功")
    print("=" * 70)
    
    if success_count > 0:
        print(f"\nJar文件已保存到: {os.path.abspath(output_dir)}")
        print("\n查看jar文件:")
        for jar_file in sorted(os.listdir(output_dir)):
            if jar_file.endswith('.jar'):
                jar_path = os.path.join(output_dir, jar_file)
                size = os.path.getsize(jar_path)
                print(f"  - {jar_file:30} ({size:>10,} 字节)")
        
        print("\n使用JD-GUI查看源码:")
        print(f"  jd-gui {output_dir}/classes.jar")
        print("\n或使用任意Java反编译工具打开jar文件")

def convert_apk_to_jar(apk_file="merged.apk", output_jar="merged.jar"):
    """直接转换APK为jar"""
    print("\n" + "=" * 70)
    print("APK转Jar".center(70))
    print("=" * 70)
    
    if not os.path.exists(apk_file):
        print(f"✗ APK文件不存在: {apk_file}")
        return False
    
    # 构建dex2jar命令
    if sys.platform == 'win32':
        d2j_script = os.path.join(DEX2JAR_DIR, "d2j-dex2jar.bat")
    else:
        d2j_script = os.path.join(DEX2JAR_DIR, "d2j-dex2jar.sh")
        os.chmod(d2j_script, 0o755)
    
    print(f"转换: {apk_file} -> {output_jar}")
    
    try:
        cmd = [d2j_script, apk_file, "-o", output_jar, "--force"]
        result = subprocess.run(cmd, capture_output=True, text=True)
        
        if result.returncode == 0 and os.path.exists(output_jar):
            size = os.path.getsize(output_jar)
            print(f"✓ 转换成功: {output_jar} ({size:,} 字节)")
            print(f"\n使用JD-GUI查看:")
            print(f"  jd-gui {output_jar}")
            return True
        else:
            print(f"✗ 转换失败: {result.stderr}")
            return False
            
    except Exception as e:
        print(f"✗ 转换失败: {e}")
        return False

def main():
    import argparse
    
    parser = argparse.ArgumentParser(description='使用dex2jar转换dex文件')
    parser.add_argument('-s', '--source', default='merged_dex',
                       help='dex文件源目录 (默认: merged_dex)')
    parser.add_argument('-o', '--output', default='jar_output',
                       help='jar文件输出目录 (默认: jar_output)')
    parser.add_argument('-a', '--apk', action='store_true',
                       help='直接转换APK文件')
    parser.add_argument('--apk-file', default='merged.apk',
                       help='APK文件路径')
    parser.add_argument('--skip-download', action='store_true',
                       help='跳过dex2jar下载')
    
    args = parser.parse_args()
    
    # 下载dex2jar
    if not args.skip_download:
        if not download_dex2jar():
            return
    
    # 转换文件
    if args.apk:
        convert_apk_to_jar(args.apk_file)
    else:
        convert_all_dex(args.source, args.output)

if __name__ == '__main__':
    main()

